//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <ddk.h>

class TimerServer001 : public CDeviceDriver
{
public:
    CARAPI Read(
        /* [in] */ UInt64 u64Offset,
        /* [in] */ UInt32 bytesToRead,
        /* [out] */ EzByteBuf buffer,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Write(
        /* [in] */ UInt64 u64Offset,
        /* [in] */ EzByteBuf buffer,
        /* [out] */ UInt32 * pBytesWritten,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Control(
        /* [in] */ Handle32 nControlCode,
        /* [in] */ EzByteBuf inBuffer,
        /* [out] */ EzByteBuf * pOutBuffer,
        /* [out] */ IEvent * * ppCompletionEvent);

    virtual void Dispose() {}

private:
    DzTimer       **m_ppTimer;
    uint_t      m_uAccount;
    uint_t      *m_puDueTick;
};

EXTERN IDeviceDriver * CDECL CreateTimerServer0(uint_t uDeviceNo, void *pvParameter)
{
    TimerServer001 *pDriver = new TimerServer001;
    if (NULL == pDriver) {
        kprintf("ERROR:There have no enough memory, %s, %d\n",
                        __FILE__, __LINE__);
        return NULL;
    }

    pDriver->AddRef();

    return pDriver;
}

ECode TimerServer001::Read(
    /* [in] */ UInt64 u64Offset,
    /* [in] */ UInt32 bytesToRead,
    /* [out] */ EzByteBuf buffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    return E_NOT_IMPLEMENTED;
}

ECode TimerServer001::Write(
    /* [in] */ UInt64 u64Offset,
    /* [in] */ EzByteBuf buffer,
    /* [out] */ UInt32 * pBytesWritten,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    return E_NOT_IMPLEMENTED;
}

void CDECL TimerCallBack0(void *pvParameter)
{
    uint_t i = 0;

    while (i++ < 0xf0000000);
}

ECode TimerServer001::Control(
    /* [in] */ Handle32 nControlCode,
    /* [in] */ EzByteBuf inBuffer,
    /* [out] */ EzByteBuf * pOutBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    if (NULL != ppCompletionEvent) {
        return E_INVALID_ARGUMENT;
    }

    ECode ec = NOERROR;

    switch (nControlCode) {
        case 0:{
            if (inBuffer.IsNull() || !pOutBuffer->IsNull()) {
                return E_INVALID_ARGUMENT;
            }

            m_uAccount = *(uint_t *)(char *)inBuffer;
            m_puDueTick = new uint_t[m_uAccount];
            if (NULL == m_puDueTick) {
                kprintf("0 No memory\n");
                return E_OUT_OF_MEMORY;
            }

            m_ppTimer = (DzTimer **)malloc(4 * m_uAccount);
            if (NULL == m_ppTimer) {
                kprintf("1 No memory\n");
                return E_OUT_OF_MEMORY;
            }

            for (uint_t i = 0; i < m_uAccount; i++) {
                m_puDueTick[i] = ((uint_t *)(char *)inBuffer)[1 + i * 2];
                m_ppTimer[i] = new DzTimer(m_puDueTick[i], TimerCallBack0,
                    (void *)((uint_t *)(char *)inBuffer)[2 + i * 2]);

                if (NULL == m_ppTimer[i]) {
                    kprintf("2 No memroy\n");
                    return E_OUT_OF_MEMORY;
                }
            }

            break;
        }

        case 1:{
            if (!inBuffer.IsNull() || !pOutBuffer->IsNull()) {
                return E_INVALID_ARGUMENT;
            }

            delete m_puDueTick;

            for (uint_t i = 0; i < m_uAccount; i++) {
                if (NULL != m_ppTimer[i]) {
                    delete m_ppTimer[i];
                }
            }

            if (NULL != m_ppTimer) {
                free(m_ppTimer);
            }

            break;
        }

        case 2:{
            if (!inBuffer.IsNull() || !pOutBuffer->IsNull()) {
                return E_INVALID_ARGUMENT;
            }

            for (uint_t i = 0; i < m_uAccount; i++) {
                m_ppTimer[i]->Start();
            }

            break;
        }

        case 3:{
            if (inBuffer.IsNull() || !pOutBuffer->IsNull()) {
                return E_INVALID_ARGUMENT;
            }

            for (uint_t i = 0; i < m_uAccount; i++) {
                m_ppTimer[i]->Restart(((uint_t *)(char *)inBuffer)[i]);
            }

            break;
        }

        case 4:{
            if (!inBuffer.IsNull() || !pOutBuffer->IsNull()) {
                return E_INVALID_ARGUMENT;
            }

            for (uint_t i = 0; i < m_uAccount; i++) {
                m_ppTimer[i]->Cancel();
            }

            break;
        }

        case 5:{
            if (!inBuffer.IsNull() || pOutBuffer->IsNull()) {
                return E_INVALID_ARGUMENT;
            }

            if ((uint_t)pOutBuffer->GetCapacity()
                    < m_uAccount * sizeof(bool_t)) {
                return E_OUT_OF_MEMORY;
            }

            for (uint_t i = 0; i < m_uAccount; i++) {
                ((bool_t *)(char *)ebbOutData)[i] = m_ppTimer[i]->Due();
            }

            break;
        }

        case 6:{
            if (!inBuffer.IsNull() || pOutBuffer->IsNull()) {
                return E_INVALID_ARGUMENT;
            }

            if ((uint_t)pOutBuffer->GetCapacity()
                    < m_uAccount * sizeof(uint_t)) {
                return E_OUT_OF_MEMORY;
            }

            uint_t i;

            for (i = 0; i < m_uAccount; i++) {
                ((uint_t *)(char *)ebbOutData)[i] =
                    m_ppTimer[i]->GetResidualTicks();
            }

            pOutBuffer->SetUsed(i * sizeof(uint_t));

            break;
        }

        default:{
            return E_NOT_IMPLEMENTED;
        }
    }

    return ec;
}
